﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;

namespace RgUtility.Orm.FastSetter
{
    /// <summary>
    /// 定义一个setValue
    /// </summary>
    /// <param name="target"></param>
    /// <param name="arg"></param>
    public delegate void SetValueDelegate(object target, object arg);

    public  static class DynamicMethodFactory
    {
        public static SetValueDelegate CreatePropertySetter(PropertyInfo property)
        {
            if (property.CanWrite == false)
                throw new NotSupportedException("属性不支持写操作。");
            //取得public 的set方法
            MethodInfo setMethod = property.GetSetMethod(false);
            DynamicMethod dm = new DynamicMethod("PropertySetter", //方法名
                null,//方法返回值类型
                new Type[] { typeof(object), typeof(object) },//方法参数：target,arg
                property.DeclaringType, //创建的动态方法关联的类。
                true//不做jit访问检查。
                );
            ILGenerator il = dm.GetILGenerator();//得到一个il生成器。
            if (!setMethod.IsStatic)//不是静态方法
            {
                il.Emit(OpCodes.Ldarg_0);//il发出流代码0。
            }
            il.Emit(OpCodes.Ldarg_1);//il发出流代码1。
            if (property.PropertyType.IsValueType)
                il.Emit(OpCodes.Unbox_Any, property.PropertyType);//object to value
            else
                il.Emit(OpCodes.Castclass, property.PropertyType);//object to T
            if (!setMethod.IsStatic && !property.DeclaringType.IsValueType)
            {
                il.EmitCall(OpCodes.Callvirt, setMethod, null);//il发出调用虚方法。
            }
            //else
            //    il.EmitCall(OpCodes.Call, setMethod, null);//il发出调用静态方法
            il.Emit(OpCodes.Ret);//返回。
            /* void PropertySetter(object  target,object arg)
             * {
             *   Setter((T)tartget,(T)arg);
             * }
             */
            return (SetValueDelegate)dm.CreateDelegate(typeof(SetValueDelegate));
        }
    }
}
